package rs.mbs2.epics.server.entity;

import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.interceptor.Interceptors;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import rs.mbs2.epics.server.session.Logger;

@SuppressWarnings("serial")
@Entity
@Table(name="users")
@Interceptors(Logger.class)
@NamedQueries({
	@NamedQuery(name = "findUserByEmailAndPassword",
			query = "SELECT u FROM User u WHERE u.emailAddress " +
					"LIKE :emailAddress AND u.password LIKE :password"),
					
	@NamedQuery(name = "findUserByEmail",
	query = "SELECT u FROM User u WHERE u.emailAddress LIKE :emailAddress"),
	
	@NamedQuery(name = "findUserThatCreatedAlbum",
	query = "SELECT u FROM User u LEFT JOIN u.albums a WHERE a.id LIKE :albumId")
		
	})
public class User implements Serializable {
	
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "user_id", unique = true, nullable = false)
	private Integer id;
	
	@Column(name = "user_email_address", unique = true, nullable = false)
	private String  emailAddress;

	@Column(name = "user_password", unique = false, nullable = false)
	private String  password;
	
	@Column(name = "user_first_name", unique = false, nullable = false)
	private String  firstname;
	
	@Column(name = "user_last_name", unique = false, nullable = false)
	private String  lastname;
	
	@Column(columnDefinition="ENUM('MALE', 'FEMALE', 'NOT_SPECIFIED')")
	private String  gender;
	
	@Column(name = "user_date_of_birth", unique = false, nullable = false)
	private Date    dateOfBirth;
	
	@Column(name = "user_email_notifications", nullable = false)
	private Boolean emailNotifications;

	@OneToOne(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER, mappedBy = "user")
//	@JoinColumn(name = "profile_image_id", referencedColumnName = "profile_image_id", nullable = true)
	private ProfileImage profileImage;
	
	@OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER, mappedBy = "user")
	private Set<Album> albums;
	
	@OneToOne(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
	@JoinColumn(name = "album_id", referencedColumnName = "album_id", nullable = true)
	private Album favouriteAlbum;
	
	@OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER, mappedBy = "userThatRated")
	private Set<Rating> ratings;
	
	@OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY, mappedBy = "user")
	private Set<Comment> comments;
	
	@ManyToMany(fetch = FetchType.EAGER, cascade = { CascadeType.ALL })
	@JoinTable( name = "followers", 
				joinColumns = { @JoinColumn(name = "user_id", nullable = false) },
				inverseJoinColumns = { @JoinColumn(name = "follower_id", referencedColumnName = "user_id", nullable = false) } )
	private Set<User> followers;

	@ManyToMany(mappedBy = "followers",fetch = FetchType.EAGER)
	private Set<User> followedUsers;
	
	public User() {
		
	}
	
	public User(String emailAddress, String password, String firstname,
			String lastname, String gender, Date dateOfBirth,
			Boolean emailNotifications, ProfileImage profileImage) {
		
		super();
		this.emailAddress = emailAddress;
		this.password = password;
		this.firstname = firstname;
		this.lastname = lastname;
		this.gender = gender;
		this.dateOfBirth = dateOfBirth;
		this.emailNotifications = emailNotifications;
		this.profileImage = profileImage;
		this.albums = new HashSet<>();
		this.ratings = new HashSet<>();
		this.comments = new HashSet<>();
		this.followers = new HashSet<>();
		this.followedUsers = new HashSet<>();
		this.favouriteAlbum = new Album("Favorites", "User's favorite photos", true, this);
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((emailAddress == null) ? 0 : emailAddress.hashCode());
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		User other = (User) obj;
		if (emailAddress == null) {
			if (other.emailAddress != null)
				return false;
		} else if (!emailAddress.equals(other.emailAddress))
			return false;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		return true;
	}
	
	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getEmailAddress() {
		return emailAddress;
	}

	public void setEmailAddress(String emailAddress) {
		this.emailAddress = emailAddress;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getFirstname() {
		return firstname;
	}

	public void setFirstname(String firstname) {
		this.firstname = firstname;
	}

	public String getLastname() {
		return lastname;
	}

	public void setLastname(String lastname) {
		this.lastname = lastname;
	}

	public String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}

	public Date getDateOfBirth() {
		return dateOfBirth;
	}

	public void setDateOfBirth(Date dateOfBirth) {
		this.dateOfBirth = dateOfBirth;
	}

	public Boolean getEmailNotifications() {
		return emailNotifications;
	}

	public void setEmailNotifications(Boolean emailNotifications) {
		this.emailNotifications = emailNotifications;
	}

	public ProfileImage getProfileImage() {
		return profileImage;
	}

	public void setProfileImage(ProfileImage profileImage) {
		this.profileImage = profileImage;
	}

	public Set<Album> getAlbums() {
		return albums;
	}

	public void setAlbums(Set<Album> albums) {
		this.albums = albums;
	}

	public Album getFavouriteAlbum() {
		return favouriteAlbum;
	}

	public void setFavouriteAlbum(Album favouriteAlbum) {
		this.favouriteAlbum = favouriteAlbum;
	}

	public Set<Rating> getRatings() {
		return ratings;
	}

	public void setRatings(Set<Rating> ratings) {
		this.ratings = ratings;
	}

	public Set<Comment> getComments() {
		return comments;
	}

	public void setComments(Set<Comment> comments) {
		this.comments = comments;
	}

	public Set<User> getFollowers() {
		return followers;
	}

	public void setFollowers(Set<User> followers) {
		this.followers = followers;
	}

	public Set<User> getFollowedUsers() {
		return followedUsers;
	}

	public void setFollowedUsers(Set<User> followedUsers) {
		this.followedUsers = followedUsers;
	}
	
}
